/*
 * Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "se_napi_oma_seservice.h"

#include <string>
#include "se_napi_oma_common.h"
#include "se_napi_oma_reader.h"

namespace OHOS {
namespace SE {
namespace KITS {

thread_local napi_ref NapiSEOmaSEService::consRef_ = nullptr;

napi_value JSOmaSEServiceClassConstructor(napi_env env, napi_callback_info info)
{
    napi_value thisVar = nullptr;
    size_t argc = ARGV_NUM_2;
    napi_value argv[ARGV_NUM_2] = {nullptr};
    napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
    // TO-DO: get paras
    NapiSEOmaSEService* omaJSClass = new NapiSEOmaSEService();

    napi_wrap(
        env, thisVar, omaJSClass,
        [](napi_env env, void* data, void* hint) {
            NapiSEOmaSEService* service = (NapiSEOmaSEService*)data;
            if (service) {
                delete service;
                service = nullptr;
            }
        },
        nullptr,
        nullptr);
    return thisVar;
}

void NapiSEOmaSEService::DefineSEOmaSEServiceJsClass(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        DECLARE_NAPI_FUNCTION("getReaders", NapiSEOmaSEService::GetReaders),
        DECLARE_NAPI_FUNCTION("isConnected", NapiSEOmaSEService::IsConnected),
        DECLARE_NAPI_FUNCTION("shutdown", NapiSEOmaSEService::Shutdown),
        DECLARE_NAPI_FUNCTION("getVersion", NapiSEOmaSEService::GetVersion),
    };
    // define JS class SEOmaSEService, JS_Constructor is the callback function
    napi_value constructor = nullptr;
    napi_define_class(env, "SEOmaSEService", NAPI_AUTO_LENGTH, JSOmaSEServiceClassConstructor,
        nullptr, sizeof(desc)/sizeof(desc[0]), desc, &constructor);
    napi_create_reference(env, constructor, 1, &consRef_);
}

napi_status NapiSEOmaSEService::CreateSEServiceInstance(napi_env env,
                                                        napi_callback_info info,
                                                        const std::string &className,
                                                        napi_value &outResult)
{
    DebugLog("Enter function NapiSEOmaSEService::CreateSEServiceInstance:");
    size_t expectedArgsCount = ARGV_NUM_2;
    size_t argc = expectedArgsCount;
    napi_value argv[ARGV_NUM_2] = {0};

    NAPI_SE_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
    NAPI_SE_RETURN_IF(argc != expectedArgsCount, "expect 2 args", napi_invalid_arg);
    if (!NapiSEOmaCommon::IsTargetValueType(env, argv[ARGV_INDEX_0], napi_string)) {
        ErrorLog("parameter type error");
        return napi_invalid_arg;
    }

    napi_value constructor = nullptr;
    NAPI_SE_CALL_RETURN(napi_get_reference_value(env, consRef_, &constructor));
    NAPI_SE_CALL_RETURN(napi_new_instance(env, constructor, argc, argv, &outResult));
    return napi_ok;
}

napi_value NapiSEOmaSEService::NewSEService(napi_env env, napi_callback_info info)
{
    napi_value result = nullptr;
    DebugLog("Enter function NapiSEOmaSEService::NewSEService:");
    auto status = CreateSEServiceInstance(env, info, "SEOmaSEService", result);
    if (status != napi_ok) {
        ErrorLog("NapiSEOmaSEService::NewSEService falied");
        return NapiSEOmaCommon::CreateUndefined(env);
    }
    return result;
}

napi_value NapiSEOmaSEService::GetReaders(napi_env env, napi_callback_info info)
{
    DebugLog("Enter function NapiSEOmaSEService::GetReaders:");
    napi_value result = nullptr;
    napi_value thisVar = nullptr;
    size_t argc = ARGV_NUM_0;
    napi_value argv[] = {nullptr};
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
    NapiSEOmaCommon::CheckArgCountAndThrow(env, argc, ARGV_NUM_0);
    // TO-DO: get readers by calling native method, throw exception when failed
    int32_t status = 0;

    if (!NapiSEOmaCommon::CheckSEStatusCodeAndThrow(env, status, "getReaders")) {
        return NapiSEOmaCommon::CreateUndefined(env);
    }
    // new instance of JS object
    napi_value constructor = nullptr;
    napi_get_reference_value(env, NapiSEOmaReader::consRef_, &constructor);
    napi_new_instance(env, constructor, argc, argv, &result);
    return result;
}

napi_value NapiSEOmaSEService::IsConnected(napi_env env, napi_callback_info info)
{
    DebugLog("Enter function NapiSEOmaSEService::IsConnected ");
    napi_value result = nullptr;
    napi_value thisVar = nullptr;
    size_t argc = ARGV_NUM_0;
    napi_value argv[] = {nullptr};
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
    NapiSEOmaCommon::CheckArgCountAndThrow(env, argc, ARGV_NUM_0);
    // TO-DO: get readers by calling native method, throw exception when failed
    int32_t status = BUSI_ERR_SE_STATE_EXCEPTION;

    if (!NapiSEOmaCommon::CheckSEStatusCodeAndThrow(env, status, "isConnected")) {
        return NapiSEOmaCommon::CreateUndefined(env);
    }
    napi_get_boolean(env, (status == SEErrorCode::ERR_NONE), &result);
    return result;
}

napi_value NapiSEOmaSEService::Shutdown(napi_env env, napi_callback_info info)
{
    DebugLog("Enter function NapiSEOmaSEService::Shutdown:");
    napi_value thisVar = nullptr;
    size_t argc = ARGV_NUM_0;
    napi_value argv[] = {nullptr};
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
    NapiSEOmaCommon::CheckArgCountAndThrow(env, argc, ARGV_NUM_0);
    // TO-DO shutdown service by call native method, throw exception when failed
    int32_t status = SEErrorCode::ERR_NONE;

    if (!NapiSEOmaCommon::CheckSEStatusCodeAndThrow(env, status, "shutdown")) {
        // output error log
    }
    return NapiSEOmaCommon::CreateUndefined(env);
}

napi_value NapiSEOmaSEService::GetVersion(napi_env env, napi_callback_info info)
{
    DebugLog("Enter function NapiSEOmaSEService::GetVersion:");
    napi_value result = nullptr;
    napi_value thisVar = nullptr;
    size_t argc = ARGV_NUM_0;
    napi_value argv[] = {nullptr};
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
    NapiSEOmaCommon::CheckArgCountAndThrow(env, argc, ARGV_NUM_0);
    // TO-DO get version by call native method, throw exception when failed
    std::string version = "1.0.0";
    int32_t status = SEErrorCode::BUSI_ERR_CAPABILITY_EXCEPTION;
    
    if (!NapiSEOmaCommon::CheckSEStatusCodeAndThrow(env, status, "getVersion")) {
        return NapiSEOmaCommon::CreateUndefined(env);
    }
    napi_create_string_utf8(env, version.c_str(), NAPI_AUTO_LENGTH, &result);
    return result;
}
} // namespace KITS
} // namespace SE
} // namespace OHOS
